package main

import "fmt"

func main() {
	//切片的扩容
	var a []int //此时这个时候并没有申请内存，是nil切片

	/*
		a[0] = 100  //索引越界，因为nil切片没有底层数组，无法赋值
		fmt.Println(a)
	*/

	//注意：切片一定要进行初始化之后才能使用，否则直接赋值，就会报错
	//如果直接对nil切片的索引位置进行赋值，会触发运行时panic

	//append()函数要有一个值来进行接收
	//a = append(a, 10)
	//fmt.Println(a)
	//注意：通过var声明的零值切片可以在append()函数直接使用，无需初始化。

	for i := 0; i < 10; i++ {
		a = append(a, i)
		fmt.Printf("%v len:%d cap:%d ptr:%p\n", a, len(a), cap(a), a)
	}
	//append的扩容是以2倍速进行扩容

	//切片可以追加多个元素
	a = append(a, 10, 11, 12, 13, 14, 15)
	fmt.Println(a)

	//切片可以追加切片
	b := []int{12, 13, 14, 15}
	a = append(a, b...)
	fmt.Println(a)

}

func main4() {
	//切片扩容相关源码:
	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.len < 1024 {
			newcap = doublecap
		} else {
			// Check 0 < newcap to detect overflow
			// and prevent an infinite loop.
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap <= 0 {
				newcap = cap
			}
		}
	}

	/*
		Go1.18版本之前的：
		首先判断，如果新申请容量（cap）大于2倍的旧容量（old.cap），最终容量（newcap）就是新申请的容量（cap）。
		否则判断，如果旧切片的长度小于1024，则最终容量(newcap)就是旧容量(old.cap)的两倍，即（newcap=doublecap），
		否则判断，如果旧切片长度大于等于1024，则最终容量（newcap）从旧容量（old.cap）开始循环增加原来的1/4，即（newcap=old.cap,for {newcap += newcap/4}）直到最终容量（newcap）大于等于新申请的容量(cap)，即（newcap >= cap）
		如果最终容量（cap）计算值溢出，则最终容量（cap）就是新申请容量（cap）。
	*/
	/*
		Go1.18版本以后
		（1)当预期的容量要大于原容量的两倍时，新的容量就是预期的容量。
		（2)当预期的容量小于或等于原容量的两倍时，如果原容量小于256，则新的容量就是
		原来的两倍；当原容量大于或等于256时，每次会扩容原来容量的1.25倍加上192，直到新
		的容量大于或等于预期容量。
		(3)实际申请的内存不是严格按照上面的规则执行的，会有一个随机数的叠加操作，

		这部分源码在GitHubGo源码的sre/runtime/slice.go文件中，从177行开始
	*/
}

//建议我们在创建切片的时候定义较大的空间，防止扩容消耗内存
